
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <glib.h>

#if HAVE_X11_XKBLIB_H
#include <X11/Xlib.h>
#endif

#include "spicy.h"
#include "vcd-common-api/vcd-util.h"
#include "vcd-common-api/vcd-log.h"
#include "vcd-common-api/trace-signals/libdebug.h"
#include "vcd-common-api/vcd-json-parser.h"
#include "vcd-common-api/vcd-crypto.h"
#include "vcd-common-api/vcd-download.h"
#include "vcd-linux-ui/vcd-start-window.h"
#include "vcd-linux-ui/vcd-message-dialog.h"
#include "vcd-rdp/vcd-rdp.h"
#include "vcd-common-api/vcd-send-heartbeat.h"

static gboolean vcdLoginClient = FALSE;
static gboolean unFullScreen = FALSE;
static gboolean openDevelopTool = FALSE;
static gboolean loginingWindow = FALSE;
static GOptionEntry vcd_cmd_entries[] = {
    {
        .long_name        = "vcd-client",
        .short_name       = 'c',
        .arg              = G_OPTION_ARG_NONE,
        .arg_data         = &vcdLoginClient,
        .description      = "use verycloud client",
    },
    {
        .long_name        = "unFullScreen",
        .short_name       = 'u',
        .arg              = G_OPTION_ARG_NONE,
        .arg_data         = &unFullScreen,
        .description      = "default is fullscreen, use '-u' un fullScreen",
    },{
        .long_name        = "debug",
        .short_name       = 'd',
        .arg              = G_OPTION_ARG_NONE,
        .arg_data         = &openDevelopTool,
        .description      = "default is false, use '-d' open",
    },{
        .long_name        = "logining-window",
        .short_name       = 'l',
        .arg              = G_OPTION_ARG_NONE,
        .arg_data         = &loginingWindow,
        .description      = "default is false, use '-l' open",
    },{
        /* end of list */
    }
};

static void write_version_info_to_log(){
#ifdef PACKAGE_VERSION
  LOG_VERSION("build version:%s", PACKAGE_VERSION);
#endif

#ifdef HAVE_STREAMSINK
  LOG_VERSION("support streamsink HAVE_STREAMSINK:%d",HAVE_STREAMSINK);
#else
  //LOG_VERSION("not support streamsink");
#endif

#ifdef HAVE_GSTVIDEO
  LOG_VERSION("support gstreamer HAVE_GSTVIDEO:%d",HAVE_GSTVIDEO);
#else
  LOG_VERSION("not support gstreamer");
#endif

#ifdef HAVE_RECONNECT
  LOG_VERSION("support reconnect HAVE_RECONNECT:%d",HAVE_RECONNECT);
#else
  //LOG_VERSION("not support reconnect");
#endif
}

void waitpidexit(int sig){
    M_DEBUG("waitpidexit sig:%d",sig);
    switch (sig)
    {
        case SIGINT:
        break;
#ifdef __linux__
        case SIGCHLD:
        while(waitpid(-1,NULL,WNOHANG) > 0){
            //M_DEBUG("waitpidexit success\n");
        }
        break;
#endif
    }
}

static void init_signal(){

#ifdef WIN32
    // TODO: test  not work
    signal(SIGINT,waitpidexit);
    signal(SIGILL,waitpidexit);
    signal(SIGSEGV,waitpidexit);
    signal(SIGBREAK,waitpidexit);
    signal(SIGABRT,waitpidexit);
#else
    //signal(SIGCHLD,waitpidexit);
#endif
}

static void show_args(int argc, char* argv[]) {
    for (int i = 0; i < argc; i++) {
        M_DEBUG("[main args] argc:%d, argv:%s", i, argv[i]);
    }
}

static gboolean parse_option_args(int argc, char* argv[], spice_connect_data* scd) {
    GOptionContext *context;
    GError *error = NULL;

    context = g_option_context_new(" - start vcd client with ui");
    g_option_context_add_main_entries(context, vcd_cmd_entries, NULL);
    g_option_context_set_ignore_unknown_options(context, TRUE);
    if (!g_option_context_parse(context, &argc, &argv, &error)) {
        g_printf("option parsing failed: %s\n", error->message);
    }
    gboolean ui_client = FALSE;
    g_printf("option parsing vclient: %d\n", vcdLoginClient);
    g_printf("option parsing debug: %d\n", openDevelopTool);

    g_option_context_free(context);

    //openDevelopTool
    vcd_log_set_debug_flag(openDevelopTool);

    return vcdLoginClient;
}

static gboolean parse_args(int argc, char* argv[], spice_connect_data* scd) {

    show_args(argc, argv);

    if (argc < 2) {
        LOG_ERROR("vclient argc < 2");
        return FALSE;
    }

    //const char* uri = "vclient://e2hvc3Q6MTkyLjE2OC4zMi41MCxwb3J0OjYxMDAwLHBhc3N3b3JkOmRhYzIxODg2MzE5MzVkZjcyZDgxMGZlODllMmZjNGNhNDRlZjNjNzh9/";
    const char* uri = argv[1];
    const char* pStart = strstr(uri, "://");
    if (!pStart) {
        LOG_ERROR("args strstr '://' error");
        sprintf(scd->fail_msg, "vclient参数解析错误，参数格式有误！");
        return  FALSE;
    }

    // ://
    pStart += 3;

#if 0
    int len = strlen(pStart);

    gchar* json_str = g_malloc0(len);
    base64_decode(pStart, len, json_str);

    M_DEBUG(json_str);

    gboolean rv = vcd_json_parser_spice_connect_data(json_str, scd);
    g_free(json_str);
#else

    int size = strlen(pStart);
    char* pEnd = pStart + size - 1;

    if (*pEnd == '\/')
        *pEnd = '\0';

    vcd_common_url_decode(pStart);
    M_DEBUG("url_decode:%s", pStart);

    char json_str[1024] = {0};
    vcd_decode_crypto(pStart, json_str);
    if (openDevelopTool)
        M_DEBUG("json_str:%s", json_str);
    gboolean rv = vcd_json_parser_spice_connect_data(json_str, scd);
    scd->success = rv;

    // check if expires
    #if 0
    if (scd->expires_in > 0) {
        gint64 now = time(0);
        M_DEBUG("now time:%lld, expires_in:%lld, now-expires_in:%lld", now,scd->expires_in, now-scd->expires_in);
    }
    #endif

#endif
    return rv;
}

void init_theme_about(spice_connect_data* scd) {

    //M_DEBUG("current dir:%s",g_get_current_dir());
    //M_DEBUG("runtime dir:%s",g_get_user_runtime_dir());
    //M_DEBUG("install_path:%s",scd->install_path);

    GtkIconTheme *theme = gtk_icon_theme_get_default();

    //char* icon_path = "C:\\Program Files (x86)\\verycloud\\VeryClient\\share\\icons";
    char* icon_path = scd->theme_path;
    if(!icon_path) return;

    //gtk_icon_theme_set_search_path(theme, &icon_path,1);
    gtk_icon_theme_prepend_search_path(theme, icon_path);

    char **ppath;
    int n = 0;
    gtk_icon_theme_get_search_path(theme, &ppath,&n);

    for(int i = 0; i < n; i++){
        char *p = ppath[i];
        //printf("theme path:[%d] : %s\n",i,p);
        //M_DEBUG("theme path:[%d] : %s",i,p);
    }
}

static void do_log4c_init(spice_connect_data scd)
{
#ifndef HAVE_LOG4C
    if(vcdLoginClient){
        vcd_log_set_filename("vclient-c");
    }else {
        vcd_log_set_filename("vclient-desk");
    }
#endif

    // init log
    #if defined(__WIN32__)
    vcd_log_init_with_logdir(scd.log4crc_path, scd.log_dir);
    #else
    vcd_log_init_with_logdir("/etc/log4crc","/var/log");//default use "/etc/log4crc" scd.log_dir is used in log4crc file
    #endif
}

int main(int argc, char *argv[])
{
    spice_connect_data scd = {0};

    // init platform
    vcd_common_init_platform();

    // init x thread
    #if defined(HAVE_X11_XKBLIB_H)
    Status t = XInitThreads();
    if (t == 0) {
        printf("XInitThreads fail");
        return -1;
    }
    #endif

    // init gtk
    gtk_init(&argc, &argv);

    #if defined(__WIN32__)
    vcd_common_init_some_path(argv[0], &scd);
    #endif

    init_theme_about(&scd);

    // init signal
    init_signal();

    // init backtrace
    debug_backtrace_init();

    // check '-c' '-l' in args
    if (parse_option_args(argc, argv, &scd)) {

        if (loginingWindow) {

            if (spicy_get_img_in_install_path("loading300x250.gif", &scd))
                vcd_message_dialog_logining_with_gif(spicy_get_img_in_install_path("loading300x250.gif", &scd), NULL);
            else
                vcd_message_dialog_logining();

        } else {
            do_log4c_init(scd);

            // wirte build log
            write_version_info_to_log();

            if (check_is_process_exist("Vclient.exe", FALSE)) {
                LOG_ERROR("[Vclient.exe] 进程已经存在, 终止当前操作");
                message_box("[Vclient.exe] 进程已经存在, 终止当前操作");
                return 0;
            }

            start_download_thread(openDevelopTool);
            vcd_client_start();
            vcd_start_window_set_full_screen(!unFullScreen);
            vcd_start_window_set_open_develop_tool(openDevelopTool);
        }
        gtk_main();
        return 0;
    }

    do_log4c_init(scd);

    //parse args
    if (!parse_args(argc, argv, &scd)) {
        LOG_ERROR("parse_args err fail_msg:%s", scd.fail_msg);
        message_box(scd.fail_msg);
        return -1;
    }

    //read_vcd_conf()之后才能获取到usb字段确保自动连接已经保存的usb设备
    read_vcd_conf();
    start_download_thread(openDevelopTool);
    start_heartbeat(&scd);

    if (scd.use_rdp) {
        vcd_rdp_start_sync(&scd);
    } else {
        vcd_spice_start_sync(&scd);
    }

    return 0;
}


